package boardgamer.yavalath.client.animation;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import boardgamer.common.client.animation.Animation;
import boardgamer.common.client.layout.HasLayout;
import boardgamer.common.client.layout.InvisibleRect;
import boardgamer.common.client.layout.LayoutGroup;
import boardgamer.common.client.layout.MutableTextLayout;
import boardgamer.yavalath.client.RenderHelper;
import boardgamer.yavalath.client.resources.ImageHandler;

/**
 * @author garysoed
 */
public class ExpandingHeaderAnimation extends Animation implements HasLayout {

  static final float STROKE_WIDTH_MAX_HEIGHT_RATIO = 0.1f;
  static final int OUTLINE_ALPHA = 255;
  static final int FILL_ALPHA = 192;

  private static final float TAN30 = (float) (1f / Math.sqrt(3));

  private static final int EXPAND_TIME = 300;
  public static final int UPDATE_PERIOD = 25;

  private int timeStep = 0;

  private final Paint hexOutlinePaint;
  private final Paint hexFillPaint;
  private final Path hex;

  private final RectF hexBoundingRect;
  private final MutableTextLayout text;
  private RectF boundingRect; // Used for caching in hot code
  private LayoutGroup group;
  private InvisibleRect hexContainer;

  public ExpandingHeaderAnimation(float maxWidth, float maxHeight, float maxTextWidth,
                                  int maxTextCount) {
    super(UPDATE_PERIOD);

    this.hexOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    this.hexOutlinePaint.setStrokeWidth(maxHeight * STROKE_WIDTH_MAX_HEIGHT_RATIO);
    this.hexOutlinePaint.setStyle(Paint.Style.STROKE);

    this.hexFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    this.hexFillPaint.setStyle(Paint.Style.FILL);

    this.hex = new Path();

    this.text = new MutableTextLayout(
        RenderHelper.instance().getHexLetterPaint(),
        maxTextWidth,
        maxTextCount,
        ImageHandler.boundSizeRatio.get(RenderHelper.instance().getHexLetterFont()));
    this.hexContainer = new InvisibleRect(0, 0, maxWidth, maxHeight);

    this.group = new LayoutGroup();
    this.group
        .add(hexContainer).atCurrentRect()
        .add(this.text).atCurrentRect()
        .horizontalAlign(LayoutGroup.HorizontalAlign.CENTER)
        .verticalAlign(LayoutGroup.VerticalAlign.CENTER);
    this.boundingRect = this.group.getBoundingRect();

    this.hexBoundingRect = new RectF();
  }

  public void display(String text, int colorToUse) {
    this.text.setText(text);

    hexFillPaint.setColor(colorToUse);
    hexFillPaint.setAlpha(FILL_ALPHA);   // WTF: setting color resets the alpha
    hexOutlinePaint.setColor(colorToUse);
    hexOutlinePaint.setAlpha(OUTLINE_ALPHA);  // WTF: setting color resets the alpha

    // Redo the layout
    this.group = new LayoutGroup();
    this.group
        .add(hexContainer).atCurrentRect()
        .add(this.text).atCurrentRect()
        .horizontalAlign(LayoutGroup.HorizontalAlign.CENTER)
        .verticalAlign(LayoutGroup.VerticalAlign.CENTER)
        .setBoundingRect(boundingRect);
  }

  @Override
  public void draw(Canvas canvas) {
    canvas.drawPath(hex, hexFillPaint);
    canvas.drawPath(hex, hexOutlinePaint);
    text.draw(canvas);
  }

  @Override
  public void setBoundingRect(RectF boundingRect) {
    group.setBoundingRect(boundingRect);
    this.boundingRect = group.getBoundingRect();
    this.hexOutlinePaint.setStrokeWidth(boundingRect.height() * STROKE_WIDTH_MAX_HEIGHT_RATIO);
  }

  @Override
  public RectF getBoundingRect() {
    return group.getBoundingRect();
  }

  @Override
  public boolean isDead() {
    return timeStep >= EXPAND_TIME;
  }

  @Override
  protected void onPeriodic() {
    timeStep += UPDATE_PERIOD;
    float targetWidth = boundingRect.width();
    float width = targetWidth / EXPAND_TIME
        * (2f * timeStep - timeStep * timeStep / EXPAND_TIME);

    hexBoundingRect.set(
        boundingRect.centerX() - width / 2,
        boundingRect.top,
        boundingRect.centerX() + width / 2,
        boundingRect.bottom);
    RenderHelper.instance().updateHoriHexPath(
        hex, hexBoundingRect, hexBoundingRect.height() / 2 * TAN30);
  }
}
